<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>带旋转的饼图</title>
    <link rel="stylesheet" href="./assets/common.css">
    <style>
        .wrapper {
            position: relative;
            height: 100%;
        }

        canvas {
            display: block;
        }

        .flag {
            position: absolute;
            bottom: 30px;
            width: 24px;
            height: 24px;
            left: 50%;
            margin-left: -12px;
            background-image: url("https://gw.alipayobjects.com/zos/rmsportal/eCukcsfJoNgSIvKtFniY.png")
        }

        #content {
          width: 100%;
          text-align: center;
        }
    </style>
</head>

<body>
    <div>
        <div class="wrapper">
            <canvas id="pieRotate"></canvas>
            <div class="flag"></div>
        </div>
        <div id="content"></div>

    </div>
    <script src="./assets/jquery-3.2.1.min.js"></script>
    <script src="../build/f2-all.js"></script>
    <script src="./assets/hammer.js"></script>
    <script>
        // 绘制饼图
        const { Util, G, Chart } = F2;
        const Matrix = G.Matrix;

        const data = [
          {name: 'A',proportion: 0.8,a: '1'},
          {name: 'B',proportion: 0.5,a: '1'},
          {name: 'C',proportion: 0.45,a: '1'},
          {name: 'D',proportion: 0.15,a: '1'},
          {name: 'E',proportion: 0.12,a: '1' },
          {name: 'F',proportion: 0.1, a: '1' },
          {name: 'G',proportion: 0.03,a: '1'}
        ];
        const chart = new Chart({
            id: 'pieRotate',
            width: window.innerWidth,
            height: window.innerWidth * 0.64,
            pixelRatio: window.devicePixelRatio
        });

        chart.source(data);
        chart.legend(false);
        chart.coord('polar', {
            transposed: true,
            radius: 0.8
        });
        chart.axis(false);
        chart.tooltip(false);

        const geom = chart.interval()
            .position('a*proportion')
            .color('name', ['#1890FF', '#41D9C7', '#2FC25B', '#FACC14', '#E6965C', '#223273', '#7564CC', '#8543E0', '#5C8EE6', '#13C2C2', '#5CA3E6'])
            .adjust('stack')
            .style({
                lineWidth: 1,
                stroke: '#fff'
            });
        chart.render();


        // 开始交互逻辑
        // 一些辅助工具类函数

        const center = chart.get('coord').center; // 极坐标的圆点
        const container = geom.get('container');
        const canvas = chart.get('canvas');
        const el = canvas.get('el');
        let animating = false; // 动画状态标识位

        function interpolateNumber(a, b) {
          a = +a;
          b -= a;
          return function (t) {
            return a + b * t;
          };
        }

        function findShapeByName(name) {
          let result;
          const shapes = geom.get('container').get('children');
          Util.each(shapes, shape => {
            const origin = shape.get('origin')._origin;
            if (origin.name === name) {
              result = shape;
              return false;
            }
          });

          return result;
        }

        function repaintChart(angle) {
          const chartCoord = chart.get('coord');
          const coordStart = chartCoord.startAngle + angle;
          const coordEnd = chartCoord.endAngle + angle;

          chart.coord('polar', {
            transposed: true,
            radius: 0.8,
            startAngle: coordStart,
            endAngle: coordEnd
          });
          chart.animate(false);
          chart.repaint();
        }

        function animation(angle, data, animateCfg) {
          const rotateAngle = Math.PI / 2 - angle;
          const diff = interpolateNumber(0, rotateAngle);
          if (rotateAngle !== 0) {
            container.animate().to(animateCfg).onFrame(t => {
              animating = true;
              const frameAngle = diff(t);

              container.setTransform([
                ['t', center.x, center.y],
                ['r', frameAngle],
                ['t', -center.x, -center.y]
              ]);

              if (t === 1) {
                animating = false;
                repaintChart(rotateAngle);

                $('#content').html(data._origin.name + ': ' + data._origin.proportion);
              }
            });
          }
        }

        let lastMouseAngle;
        let totalAngle;
        chart.pluginGesture({
          options: {
            useCalculate: false, // 计算手势数据点，如果不需要可以关闭提高性能
            useOffset: false // 计算数据是否需要计算图表相对页面偏移的坐标。当图表宽度超出, scroll模式，计算位置需要加上滚动记录
          },
          gesture: {
            tap: (data, e) => {
              if (animating) return;
              const currentPoint = e.center;
              const record = chart.getSnapRecords(currentPoint)[0];

              if (!record) return;

              const shape = findShapeByName(record._origin.name);
              if (shape) {
                const startAngle = shape.attr('startAngle');
                const endAngle = shape.attr('endAngle');
                let middleAngle = (startAngle + endAngle) / 2;

                if (startAngle > endAngle && endAngle <= 0) {
                  middleAngle = (Math.PI * 2 - Math.abs(startAngle - endAngle)) / 2 + startAngle;

                  if (middleAngle > 1.5 * Math.PI) {
                    middleAngle = middleAngle - 2 * Math.PI;
                  }
                }
                animation(middleAngle, record, {
                  duration: 650,
                  easing: 'backOut'
                });
              }
            },
            'panstart panmove panend': (data, e) => {
              if (animating) return;
              const currentPoint = e.center;
              const newMouseAngle = Math.atan2(currentPoint.y - center.y, currentPoint.x - center.x) + Math.PI;

              if (e.type === 'panstart') {
                lastMouseAngle = newMouseAngle;
                totalAngle = 0;
              } else if (e.type === 'panmove') {
                const diffAngle = newMouseAngle - lastMouseAngle;
                totalAngle += diffAngle;
                container.transform([
                  ['t', center.x, center.y],
                  ['r', diffAngle],
                  ['t', -center.x, -center.y]
                ]);
                canvas.draw();
              } else if (e.type === 'panend') {
                repaintChart(totalAngle);

                const shapes = container.get('children');
                let middleAngle = Math.PI * 0.5;
                let rotateShape;
                Util.each(shapes, s => {
                  const startAngle = s.attr('startAngle');
                  const endAngle = s.attr('endAngle');

                  if (startAngle <= Math.PI * 0.5 && endAngle >= Math.PI * 0.5) {
                    rotateShape = s;
                    middleAngle = (startAngle + endAngle) / 2;
                    return false;
                  }
                });

                animation(middleAngle, rotateShape.get('origin'), {
                  duration: 250,
                  easing: 'backOut'
                });
              }

              lastMouseAngle = newMouseAngle;
            }
          }
        });

/*
        const hammer = new Hammer(el);
        // 点击操作
        hammer.on('tap', e => {
          if (animating) return;
          const currentPoint = e.center;
          const record = chart.getSnapRecords(currentPoint)[0];

          if (!record) return;

          const shape = findShapeByName(record._origin.name);
          if (shape) {
            const startAngle = shape.attr('startAngle');
            const endAngle = shape.attr('endAngle');
            let middleAngle = (startAngle + endAngle) / 2;

            if (startAngle > endAngle && endAngle <= 0) {
              middleAngle = (Math.PI * 2 - Math.abs(startAngle - endAngle)) / 2 + startAngle;

              if (middleAngle > 1.5 * Math.PI) {
                middleAngle = middleAngle - 2 * Math.PI;
              }
            }
            animation(middleAngle, {
              duration: 650,
              easing: 'backOut'
            });
          }
        });


        let lastMouseAngle;
        let totalAngle;
        hammer.on('panstart panmove panend', e => {
          if (animating) return;
          const currentPoint = e.center;
          const newMouseAngle = Math.atan2(currentPoint.y - center.y, currentPoint.x - center.x) + Math.PI;

          if (e.type === 'panstart') {
            lastMouseAngle = newMouseAngle;
            totalAngle = 0;
          } else if (e.type === 'panmove') {
            const diffAngle = newMouseAngle - lastMouseAngle;
            totalAngle += diffAngle;
            container.transform([
              ['t', center.x, center.y],
              ['r', diffAngle],
              ['t', -center.x, -center.y]
            ]);
            canvas.draw();
          } else if (e.type === 'panend') {
            repaintChart(totalAngle);

            const shapes = container.get('children');
            let middleAngle = Math.PI * 0.5;
            Util.each(shapes, s => {
              const startAngle = s.attr('startAngle');
              const endAngle = s.attr('endAngle');

              if (startAngle <= Math.PI * 0.5 && endAngle >= Math.PI * 0.5) {
                rotateShape = s;
                middleAngle = (startAngle + endAngle) / 2;
                return false;
              }
            });

            animation(middleAngle, {
              duration: 350,
              easing: 'backOut'
            });
          }

          lastMouseAngle = newMouseAngle;
        });
*/
    </script>
</body>
</html>
